﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace PSE.AuditLogging.Common
{
    /// <summary>
    /// Classe que provê uma forma padronizada de controlar re-execução de acordo com o número máximo de tentativas e
    /// o tempo de aguardo antes de uma nova tentativa
    /// </summary>
    public class OperationRetryControl
    {
        /// <summary>
        /// Armazena as informações para controle de re-execução
        /// </summary>
        internal class OperationRetryInformation
        {
            internal string OperationId
            {
                get;
                set;
            }

            internal TimeSpan TimeToWait
            {
                get;
                set;
            }

            internal int MaxAttempts
            {
                get;
                set;
            }

            internal int Attempts
            {
                get;
                set;
            }
        }

        private Dictionary<string, OperationRetryInformation> _retryInfomations;

        /// <summary>
        /// Construtor padrão da classe
        /// </summary>
        public OperationRetryControl()
        {
            _retryInfomations = new Dictionary<string, OperationRetryInformation>();
        }

        /// <summary>
        /// Adicionar informações para controle de re-execução
        /// </summary>
        /// <param name="key">Chave de identificação das informações de controle de re-execução</param>
        /// <param name="timeToWait">Tempo de espera entre uma execução e outra</param>
        /// <param name="maxAttempts">Número máximo de tentativas</param>
        public void AddRetryControlInformation(string key, TimeSpan timeToWait, int maxAttempts)
        {
            OperationRetryInformation info = new OperationRetryInformation()
            {
                OperationId = key,
                TimeToWait = timeToWait,
                MaxAttempts = maxAttempts,
                Attempts = 0
            };

            _retryInfomations.Add(info.OperationId, info);
        }

        /// <summary>
        /// Verifica se pode re-executar 
        /// </summary>
        /// <param name="key">Chave de identificação</param>
        /// <returns></returns>
        public bool CanRetry(string key)
        {
            if (_retryInfomations.ContainsKey(key))
            {
                OperationRetryInformation retryInfo = _retryInfomations[key];

                if (retryInfo.Attempts < retryInfo.MaxAttempts)
                {
                    retryInfo.Attempts++;
                    Thread.Sleep(retryInfo.TimeToWait);
                    return true;
                }
                else
                    return false;
            }
            else
                return false;

        }

        /// <summary>
        /// Reinicia o contador de tentativas de execução
        /// </summary>
        /// <param name="key">Chave de identificação</param>
        public void Reset(string key)
        {
            if (_retryInfomations.ContainsKey(key))
            {
                OperationRetryInformation retryInfo = _retryInfomations[key];
                retryInfo.Attempts = 0;
            }
        }
    }
}
